/**
 * Project Name:kany-project-blog-web
 * File Name:SecurityFilter.java
 * Package Name:me.kany.project.blog.resource.filter
 * Date:2016年9月21日下午1:56:11
 * Copyright (c) 2016, Jason.Wang All Rights Reserved.
 */
package me.kany.project.blog.resource.filter;

import java.io.IOException;
import java.security.Key;
import java.util.Arrays;

import javax.annotation.Priority;
import javax.inject.Inject;
import javax.servlet.ServletContext;
import javax.ws.rs.Priorities;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerRequestFilter;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;
import javax.ws.rs.ext.Provider;

import org.glassfish.jersey.server.ContainerRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import me.kany.project.blog.resource.model.AuthorPricinple;
import me.kany.project.blog.resource.model.User;
import me.kany.utils.token.KeyUtil;
import me.kany.utils.token.TokenUtil;

/**
 * ClassName:SecurityFilter<br/>
 * Function: 用来做安全验证的拦截<br/>
 * Date:2016年9月21日下午1:56:11<br/>
 * 
 * @author Jason.Wang
 * @version 1.0
 * @since JDK1.7
 * @see
 */
// 实现该拦截器借口
// @Provider可以自动注册
@Provider
@Priority(Priorities.AUTHENTICATION) // 优先级最高
public class SecurityFilter implements ContainerRequestFilter {

	private final static Logger logger = LoggerFactory.getLogger(SecurityFilter.class.getCanonicalName());
	// @Autowired
	// UserService userservice;
	@Context
	private ServletContext context;
	@Inject
	private javax.inject.Provider<UriInfo> uriInfo;

	public static String extractJwtTokenFromAuthorizationHeader(String auth) {
		// Replacing "Bearer Token" to "Token" directly
		return auth.replaceFirst("[B|b][E|e][A|a][R|r][E|e][R|r] ", "").replace(" ", "");
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see javax.ws.rs.container.ContainerRequestFilter#filter(javax.ws.rs.container.ContainerRequestContext)
	 */
	@Override
	public void filter(ContainerRequestContext containerRequestContext) throws IOException {
		// 获取本地的私钥
		Key key = KeyUtil.getKey(context);
		// 得到访问的方法 例如GET,POST
		String method = containerRequestContext.getMethod().toLowerCase();
		// 得到访问路径
		String path = ((ContainerRequest) containerRequestContext).getPath(true).toLowerCase();
		// get application.wadl和application.wadl/xsd0.xsd不需要验证，post验证过滤,注册过滤。
		if (("get".equals(method) && ("application.wadl".equals(path) || "application.wadl/xsd0.xsd".equals(path))) || ("post".equals(method) && ("authentication".equals(path) || "regist".equals(path))) || ("get".equals(method) && path.startsWith("common"))) {
			// pass through the filter.
			containerRequestContext.setSecurityContext(new SecurityContextAuthorizer(uriInfo, new AuthorPricinple("anonymous"), new String[] { "anonymous" }));
			return;
		}

		// 获取头信息中的token
		String authorizationHeader = ((ContainerRequest) containerRequestContext).getHeaderString("authtoken");
		// 如果token为空抛出
		if (authorizationHeader == null) {
			throw new WebApplicationException(Response.Status.UNAUTHORIZED);// 抛出未认证的错误
		}
		// 把Bear Token换成Token
		String strToken = extractJwtTokenFromAuthorizationHeader(authorizationHeader);
		if (TokenUtil.isValid(strToken, key)) {
			String name = TokenUtil.getName(strToken, key);// 反解出Name
			String[] roles = TokenUtil.getRoles(strToken, key);// 反解出角色
			int version = TokenUtil.getVersion(strToken, key);// 得到版本
			if (name != null && roles.length != 0 && version != -1) {
				User user = new User();
				user.setRoles(new String[] { "user" });
				if (user.getVersion() == version && user.getRoles() != null && Arrays.asList(user.getRoles()).containsAll(Arrays.asList(roles))) {
					containerRequestContext.setSecurityContext(new SecurityContextAuthorizer(uriInfo, new AuthorPricinple(name), roles));
					return;
				} else {
					logger.info("Version or roles did not match the token");
				}
			} else {
				logger.info("name, roles or version missing from token");
			}
		} else {
			logger.info("token is invalid");
		}
		logger.info(strToken);
		throw new WebApplicationException(Response.Status.UNAUTHORIZED);
	}

}
